﻿using System;
using System.Collections.Generic;
using System.Linq;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using YJKRGeometry;
using Transfer.CommonUnit;

namespace YJKArchMethodLibrary.BreakWallByLevel
{
	public class WallBreakManager
	{
		public WallBreakManager(Document doc)
		{
			this.m_doc = doc;
		}

		public Result BreakByLevel(List<Wall> walls, List<Level> levels, ref List<ElementId> lstNewWallId, bool hasProgressBar = false, Assist.WindowHandle hWndRevit = null)
		{
			Transaction transaction = new Transaction(this.m_doc, "按层分墙");
			Result result;
			try
			{
				transaction.Start();
				List<Wall> list = new List<Wall>();
				foreach (Wall wall in walls)
				{
					if ((int)wall.WallType.Kind == 2)
					{
						lstNewWallId.Add(wall.Id);
					}
					else
					{
						list.Add(wall);
					}
				}
				List<KeyValuePair<int, string>> list2 = new List<KeyValuePair<int, string>>();
				int num = 1;
				int num2 = 0;
				foreach (Wall wall2 in list)
				{
					num2 += this.BreakNumber(levels, wall2);
					int num3 = -1;
					int num4 = -1;
					ElementId invalidElementId = ElementId.InvalidElementId;
					if (this.PartitionFloor(wall2, levels, ref num3, ref num4))
					{
						string value = string.Concat(new string[]
						{
							"wall",
							num.ToString(),
							"(Id:",
							wall2.Id.ToString(),
							")"
						});
						int key = num4 - num3 + 2;
						KeyValuePair<int, string> item = new KeyValuePair<int, string>(key, value);
						list2.Add(item);
						num++;
					}
				}
				MyProgressBar myProgressBar = null;
				if (hasProgressBar)
				{
					myProgressBar = new MyProgressBar(hWndRevit, list2, "按层分墙", true);
				}
				foreach (Wall wall3 in list)
				{
					if (!this.BreakWall(levels, wall3, ref lstNewWallId, ref myProgressBar))
					{
						break;
					}
				}
				if (myProgressBar != null && myProgressBar.IsStoped)
				{
					transaction.RollBack();
				}
				else
				{
					transaction.Commit();
				}
				if (myProgressBar != null)
				{
					myProgressBar.Dispose();
				}
				result = Autodesk.Revit.UI.Result.Succeeded;
			}
			catch (Exception)
			{
				transaction.RollBack();
				result = Autodesk.Revit.UI.Result.Failed;
			}
			return result;
		}

		private int BreakNumber(List<Level> levels, Wall wall)
		{
			ElementId elementId = wall.get_Parameter(BuiltInParameter.WALL_BASE_CONSTRAINT).AsElementId();
			Level level = this.m_doc.GetElement(elementId) as Level;
			double num = wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).AsDouble();
			double num2 = wall.get_Parameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM).AsDouble();
			double num3 = level.Elevation + num;
			double num4 = num3 + num2;
			List<Level> list = new List<Level>();
			foreach (Level level2 in levels)
			{
				if (num3 < level2.Elevation && level2.Elevation < num4)
				{
					list.Add(level2);
				}
			}
			return list.Count;
		}

		private bool BreakWall(List<Level> levels, Wall wall, ref List<ElementId> lstBreakWallId, ref MyProgressBar myProgress)
		{
			ElementId elementId = wall.get_Parameter(BuiltInParameter.WALL_BASE_CONSTRAINT).AsElementId();
			Level level = this.m_doc.GetElement(elementId) as Level;
			double num = wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).AsDouble();
			double num2 = wall.get_Parameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM).AsDouble();
			double num3 = level.Elevation + num;
			double num4 = num3 + num2;
			List<Level> list = new List<Level>();
			foreach (Level level2 in levels)
			{
				if (num3 < level2.Elevation && level2.Elevation < num4)
				{
					list.Add(level2);
				}
			}
			lstBreakWallId.Add(wall.Id);
			if (list.Count == 0)
			{
				return true;
			}
			List<ElementId> elementAttachedWall = this.GetElementAttachedWall(wall);
			Level level3 = level;
			for (int i = 0; i < list.Count; i++)
			{
				int elementCount = MirrorOperater.GetElementCount(this.m_doc);
				ICollection<ElementId> source = ElementTransformUtils.CopyElement(this.m_doc, wall.Id, XYZ.Zero);
				Wall wall2 = this.m_doc.GetElement(source.ElementAt(0)) as Wall;
				lstBreakWallId.Add(wall2.Id);
				List<ElementId> elementsIdAfter = MirrorOperater.GetElementsIdAfter(elementCount, this.m_doc);
				Level level4 = list[i];
				this.RemoveElementsExceedWall(num3, level4.Elevation, wall2, elementsIdAfter);
				if (i > 0)
				{
					wall2.get_Parameter(BuiltInParameter.WALL_BASE_CONSTRAINT).Set(level3.Id);
					wall2.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).Set(0);
				}
				wall2.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).Set(level4.Id);
				wall2.get_Parameter(BuiltInParameter.WALL_TOP_OFFSET).Set(0);
				level3 = level4;
				num3 = level3.Elevation;
				if (myProgress != null && !myProgress.ProgressStep(1) && myProgress.IsStoped)
				{
					return false;
				}
			}
			this.RemoveElementsExceedWall(num3, num4, wall, elementAttachedWall);
			wall.get_Parameter(BuiltInParameter.WALL_BASE_CONSTRAINT).Set(level3.Id);
			wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).Set(0);
			ElementId elementId2 = wall.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).AsElementId();
			if (ElementId.InvalidElementId == elementId2)
			{
				wall.get_Parameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM).Set(num4 - level3.Elevation);
			}
			return myProgress == null || myProgress.ProgressStep(1) || !myProgress.IsStoped;
		}

		private List<ElementId> GetElementAttachedWall(Wall wall)
		{
			List<ElementId> list = new List<ElementId>();
			IEnumerable<Element> enumerable = new FilteredElementCollector(this.m_doc).OfClass(typeof(FamilyInstance)).ToElements();
			ICollection<Element> collection = new FilteredElementCollector(this.m_doc).OfClass(typeof(Opening)).ToElements();
			foreach (Element element in enumerable)
			{
				FamilyInstance familyInstance = element as FamilyInstance;
				if (familyInstance != null && familyInstance.Host != null && familyInstance.Host != null && familyInstance.Host.Id == wall.Id)
				{
					list.Add(element.Id);
				}
			}
			foreach (Element element2 in collection)
			{
				Opening opening = element2 as Opening;
				if (opening.Host != null && opening.Host.Id == wall.Id)
				{
					list.Add(element2.Id);
				}
			}
			return list;
		}

		private void RemoveElementsExceedWall(double baseLevelValue, double topLevelValue, Wall wall, List<ElementId> ids)
		{
			if ((int)wall.WallType.Kind == 1)
			{
				return;
			}
			foreach (ElementId elementId in ids)
			{
				Element element = this.m_doc.GetElement(elementId);
				FamilyInstance familyInstance = element as FamilyInstance;
				if (familyInstance != null)
				{
					ElementId elementId2 = familyInstance.get_Parameter(BuiltInParameter.FAMILY_LEVEL_PARAM).AsElementId();
					double elevation = (this.m_doc.GetElement(elementId2) as Level).Elevation;
					double num = familyInstance.get_Parameter(BuiltInParameter.INSTANCE_SILL_HEIGHT_PARAM).AsDouble();
					double num2 = familyInstance.get_Parameter(BuiltInParameter.INSTANCE_HEAD_HEIGHT_PARAM).AsDouble();
					num += elevation;
					num2 += elevation;
					if (num >= baseLevelValue && num < topLevelValue)
					{
						if (num2 < baseLevelValue)
						{
							continue;
						}
						if (num2 > topLevelValue)
						{
							continue;
						}
					}
					else
					{
						this.m_doc.Delete(element.Id);
					}
				}
				Opening opening = element as Opening;
				if (opening != null)
				{
					ElementId elementId3 = opening.get_Parameter(BuiltInParameter.WALL_BASE_CONSTRAINT).AsElementId();
					double num3 = (this.m_doc.GetElement(elementId3) as Level).Elevation;
					ElementId elementId4 = opening.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).AsElementId();
					double num4 = (this.m_doc.GetElement(elementId4) as Level).Elevation;
					double num5 = opening.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).AsDouble();
					double num6 = opening.get_Parameter(BuiltInParameter.WALL_TOP_OFFSET).AsDouble();
					num3 += num5;
					num4 += num6;
					if (num3 >= baseLevelValue && num3 < topLevelValue)
					{
						if (num4 >= baseLevelValue && num4 > topLevelValue)
						{
						}
					}
					else
					{
						this.m_doc.Delete(element.Id);
					}
				}
			}
		}

		private bool PartitionFloor(Wall wall, List<Level> levels, ref int findMinLevelIndex, ref int findMaxLevelIndex)
		{
			double bottomElevation = this.GetBottomElevation(wall);
			ElementId elementId = wall.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).AsElementId();
			double val;
			if (ElementId.InvalidElementId == elementId)
			{
				double num = wall.get_Parameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM).AsDouble();
				val = bottomElevation + num;
			}
			else
			{
				double num2 = wall.get_Parameter(BuiltInParameter.WALL_TOP_OFFSET).AsDouble();
				val = (this.m_doc.GetElement(elementId) as Level).Elevation + num2;
			}
			findMinLevelIndex = -1;
			findMaxLevelIndex = -1;
			for (int i = 0; i < levels.Count; i++)
			{
				if (-1 == findMinLevelIndex)
				{
					if (Geometry.GreaterThan(levels[i].Elevation, bottomElevation))
					{
						findMinLevelIndex = i;
					}
				}
				else if (-1 == findMaxLevelIndex && Geometry.Greaterthan_Or_Equal(levels[i].Elevation, val))
				{
					findMaxLevelIndex = i - 1;
					break;
				}
			}
			if (-1 == findMinLevelIndex)
			{
				return false;
			}
			if (-1 == findMaxLevelIndex)
			{
				findMaxLevelIndex = levels.Count - 1;
			}
			return true;
		}

		private double GetBottomElevation(Wall wall)
		{
			ElementId elementId = wall.get_Parameter(BuiltInParameter.WALL_BASE_CONSTRAINT).AsElementId();
			double num = wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).AsDouble();
			return (this.m_doc.GetElement(elementId) as Level).Elevation + num;
		}

		private Document m_doc;
	}
}
